import unittest
from collections import Iterable
"""
@overload def max(iterable: Iterable[_T], key: (_T) -> Any = ..., default: _T = ...) -> _T 
Possible types: 
• (arg1: _T, arg2: _T, args: Tuple[_T, ...], key: (_T) -> Any) -> _T 
• (iterable: Iterable[_T], key: (_T) -> Any, default: _T) -> _T
"""
def my_max(*args, key=None, default=None):
    if len(args) == 1 and isinstance(args[0], Iterable):
        # 情况1.max(iterable, *[, default=obj, key=func]) -> value
        if len(args[0]) == 0:
            # (a).iterable是空的时返回default
            return default
        # (b).取出args[0]的以key的函数对象为判断的标准的最大值
        if callable(key):
            max_num = args[0][0]
            for i in args[0][1:]:
                if key(i) > key(max_num):
                    max_num = i
            return max_num
        # (c).取出args[0]的最大值
        max_num = args[0][0]
        for i in args[0][1:]:
            if i > max_num:
                max_num = i
        return max_num
    elif len(args) > 1:
        # 情况2.max(arg1, arg2, *args, *[, key=func]) -> value
        # (a).取出args[0]的以key的函数对象为判断的标准的最大值
        if callable(key):
            max_num = args[0]
            for x in args[1:]:
                if key(x) > key(max_num):
                    max_num = x
            return max_num
        # (b).取出args[0]的最大值
        max_num = args[0]
        for x in args[1:]:
            if x > max_num:
                max_num = x
        return max_num
    else:
        # len(args) ==1 但是args[0]不可迭代，或者len(args)<1,都是参数错误
        raise Exception('参数错误')


class TestMax(unittest.TestCase):
    def test_max_none(self):
        obj = []
        self.assertEqual(max(obj, default=0), my_max(obj, default=0))

    def test_max_iterable(self):
        obj = [1, 4, -5]
        self.assertEqual(max(obj), my_max(obj))
        # 带有key的函数测试
        self.assertEqual(max(obj, key=abs), my_max(obj, key=abs))

    def test_max_more_args(self):
        obj = 1, 4, -5
        self.assertEqual(max(obj), my_max(obj))
        # 带有key的函数测试
        self.assertEqual(max(obj, key=abs), my_max(obj, key=abs))

    def test_max_more_with_tuple(self):
        obj = (1, 2), (3, 5), (3, 7), (2, 1)
        self.assertEqual(max(obj), my_max(obj))


if __name__ == '__main__':
    unittest.main()
